﻿using System;
using System.IO;
using Log;
using Newtonsoft.Json;

namespace RegLog
{
    /// <summary>
    /// Classe para registro de logs em arquivo JSON.
    /// </summary>
    public class LogJSON : ILog
    {
        /// <summary>
        /// Informa se o arquivo de log existente será ou não substituido.
        /// </summary>
        public bool SubstituirArquivo { get; set; }
        /// <summary>
        /// Nome do arquivo de log a ser utilizado.
        /// </summary>
        public string NomeArquivo { get; set; }
        private string caminhoArquivo;
        /// <summary>
        /// Caminho completo do repositório do arquivo de log.
        /// </summary>
        public string CaminhoArquivo
        {
            get
            {
                return caminhoArquivo;
            }
            set
            {
                caminhoArquivo = value;
                if (caminhoArquivo.LastIndexOf('\\') < caminhoArquivo.Length - 1)
                    caminhoArquivo += "\\";
            }
        }

        private struct ConteudoJSON
        {
            public DateTime dataHora;
            public string tipoLog;
            public string descricao;
            public string excecaoMensagem;
            public string excecaoSource;
            public string excecaoStackTrace;
            public string excecaoTargetSite;
        }
        
        /// <summary>
        /// Contrutor que define os dados do XML de log e seu método de gravação
        /// </summary>
        /// <param name="caminhoArquivo">Caminho onde o arquivo de log está gravado ou será criado.</param>
        /// <param name="nomeArquivo">Nome para o arquivo de log.</param>
        /// <param name="substituirArquivo">Define se o arquivo de log será substituido ou apenas incrementado. Utilize true para substituir o arquivo, o contrário para adicinoar registros ao arquivo existente.</param>
        public LogJSON(string caminhoArquivo, string nomeArquivo, bool substituirArquivo)
        {
            NomeArquivo = nomeArquivo;
            CaminhoArquivo = caminhoArquivo;
            SubstituirArquivo = substituirArquivo;
        }

        /// <summary>
        /// Registrar o evento de log em XML.
        /// </summary>
        /// <param name="sender">Objeto gerador do registro de log.</param>
        /// <param name="e">Objeto que contém o log.</param>
        /// <param name="ret">Utilizado para retornar o resultado da execução à aplicação chamadora.</param>
        public void Log(object sender, EventosLogEventArgs e, out int ret)
        {           
            if (!Directory.Exists(CaminhoArquivo)) Directory.CreateDirectory(CaminhoArquivo);
            if (!string.IsNullOrEmpty(CaminhoArquivo) && !string.IsNullOrEmpty(NomeArquivo))
            {
                try
                {
                    var conteudo = new ConteudoJSON
                    {
                        dataHora = e.DataHora,
                        tipoLog = e.TipoLogString,
                        descricao = e.Descricao,
                        excecaoMensagem = e.Exception.Message,
                        excecaoSource = e.Exception.Source,
                        excecaoStackTrace = e.Exception.StackTrace,
                        excecaoTargetSite = e.Exception.TargetSite.ToString()
                    };
                    string logConteudo = JsonConvert.SerializeObject(conteudo);
                    string arquivo = CaminhoArquivo + NomeArquivo;
                    if (SubstituirArquivo && File.Exists(arquivo)) File.Delete(arquivo);
                    var modoGravacao = SubstituirArquivo ? FileMode.CreateNew : FileMode.Append;
                    var modoAcesso = modoGravacao == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite;
                    var log = new FileStream(arquivo, modoGravacao, modoAcesso);
                    var escrita = new StreamWriter(log, System.Text.Encoding.Default);
                    escrita.Flush();
                    escrita.Write(logConteudo);
                    escrita.Flush();
                    escrita.Close();
                    log.Close();
                    ret = 0;
                }
                catch (Exception ex)
                {
                    ret = -1;
                    throw ex;
                }
            }
            else
            {
                ret = -1;
                throw new Exception("Arquivo de log não encontrado");
            }
        }
    }
}
